package cheme.ProcessModel.ProcessUnits.Streams.Tags;

import java.io.IOException;
import java.io.Serializable;

import org.w3c.dom.Element;

import cheme.ProcessModel.AbstractParent;
import cheme.ProcessModel.ChemePropertyChangeEvent;
import cheme.ProcessModel.IChild;
import cheme.ProcessModel.IInterpretable;
import cheme.ProcessModel.IModelElement;
import cheme.ProcessModel.IPropertyAware;
import cheme.ProcessModel.ModelEnv;
import cheme.ProcessModel.ProcessModelConstants;
import cheme.ProcessModel.Visitors.IModelVisitor;

public class Tag extends AbstractParent<IChild> implements Serializable, IInterpretable
{
	/*
	 * Serialization version identifier. (Set to default for now)
	 */
	
	private static final long serialVersionUID = 1L;
	
	/*
	 * Default indices of this model element's primary children.
	 */
	
	public static final int OVERALL_INDEX = 0;
	public static final int LIST_INDEX = 1;
	
	public Tag(IModelElement parent)
	{
		super(parent);
	}
	
	/*
	 * Some model elements will need a two step initialization, the first to create and hook model to editpart layer,
	 * a second to add initial children and such that need to invoke unpdates in that editpart layer
	 */
	public void initialize()
	{
		OverallTagComponent overall = (OverallTagComponent)ModelEnv.getInstanceFor(this).createModelElement(ProcessModelConstants.TAG_OVERALL, this);
		add(overall, OVERALL_INDEX);
		
		TagComponentList list = (TagComponentList)ModelEnv.getInstanceFor(this).createModelElement(ProcessModelConstants.TAG_COMPONENT_LIST, this);
		add(list, LIST_INDEX);
		
		list.setNamingPolicy(new TagComponentInitPolicy(overall, list));
		list.initialize();
	}
	
	public void initializeXml()
	{
		OverallTagComponent overall = (OverallTagComponent)ModelEnv.getInstanceFor(this).createModelElement(ProcessModelConstants.TAG_OVERALL, this);
		add(overall, OVERALL_INDEX);
		
		TagComponentList list = (TagComponentList)ModelEnv.getInstanceFor(this).createModelElement(ProcessModelConstants.TAG_COMPONENT_LIST, this);
		add(list, LIST_INDEX);
		
		list.setNamingPolicy(new TagComponentInitPolicy(overall, list));
	}
	
	public void addBlankRow()
	{
		TagComponentList list = (TagComponentList)this.get(LIST_INDEX);
		((TagComponentInitPolicy)list.initPolicy).setCurrentId(list.getChildren().size());
		list.initialize();
	}
	
	 private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
	 {
		 //System.out.println("Tag . readObject -- start");
		 
		 /*
		  * Make sure the interpreter can listen to my changes.
		  * Specifically, when the overall tag component is added to this tag, the addition needs to
		  * trigger an initial interpretation of that overall component. Likewise, removal (which in this 
		  * particular case wont happen but in general may) needs to be processed too.
		  */
		 
		 ModelEnv.getInstanceFor(getRoot()).hookModelElement(this);
		 
		 /*
		  * Make sure I can listen to my children created form a past session.
		  */
		 
		 for(IChild child : getChildren())
		 {
			 child.addPropertyChangeListener(this);
			 
			 /*
			  * Initiate an interpretation of the re-instantiated elements.
			  */
			 
//			 firePropertyChange(P_CHILD, null, child);
		 }
		 
		 //System.out.println("Tag . readObject -- end");
	 }
	 
	/**
	 * The OverallTagComponent describes the "overall flow" of the stream. It has not material field as info is contained in the component list.
	 */
	public OverallTagComponent getOverallTag()
	{
		if(getChildren().size() > OVERALL_INDEX)
		{
			return (OverallTagComponent)get(OVERALL_INDEX);
		}
		
		return null;
	}
	
	/*
	 * Contains quantity and material descriptors of the chemical composition of the stream
	 */
	public TagComponentList getTagComponentList()
	{
		if(getChildren().size() > LIST_INDEX)
		{
			return (TagComponentList)get(LIST_INDEX);
		}
		
		return null;
	}
	
//	@Override
//	public void add(IChild child)
//	{
//		/*
//		 * Make sure the interpreter can listen to the list changes.
//		 * Specifically, when a tag component is added to this list, the addition needs to
//		 * trigger an initial interpretation of that component. Likewise, removal needs to be processed.
//		 * 
//		 * Likewise for the overall tag components...
//		 */
//		 
////		ModelEnv.getInstanceFor(getRoot()).hookModelElement(child);
//		 
//		super.add(child);
//	}
	
//	@Override
//	public void add(IChild child, int index)
//	{
//		/*
//		 * Make sure the interpreter can listen to the list changes.
//		 * Specifically, when a tag component is added to this list, the addition needs to
//		 * trigger an initial interpretation of that component. Likewise, removal needs to be processed.
//		 */
//		 
////		ModelEnv.getInstanceFor(getRoot()).hookModelElement(child);
//		
//		super.add(child, index);
//	}
			
	@Override
	protected String getToStringSeparator()
	{
		return "\n************************************\n";
	}
	
	@Override
	public String toString()
	{
		return getOverallTag().toString() + getToStringSeparator() + (null != getTagComponentList() ? getTagComponentList().toString() : "");
	}
	
	/*
	 * Note that this is intercepting the fireing of events due to adding or removing equation tokens, 
	 * this method does not respond to events from the child elements such as text change.
	 */
	@Override
	public void firePropertyChange(ChemePropertyChangeEvent evt)
	{
		super.firePropertyChange(evt);
		
		if(evt.getPropertyName().equals(IPropertyAware.P_CHILD) || //change in children set membership--common, this one.
			evt.getPropertyName().equals(IPropertyAware.P_CHILDREN))//ditto
		{
			super.firePropertyChange(
					new ChemePropertyChangeEvent(this, P_INTERPRETABLE, evt.getOldValue(), evt.getNewValue(), evt));
		}
	}
	
//	@Override
//	protected void handleTextChange(PropertyChangeEvent evt)
//	{
////		firePropertyChange(evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
//	}
	
	public Object accept(IModelVisitor ruleChecker)
	{
		return ruleChecker.visit(this);
	}
	
	public String toXml()
	{
		return super.toXml("Tag");
	}
}
